package org.com.wlc.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * @author 王立朝
 * @description  切面
 *                  切入点和通知的抽象
 *                  定义 切入点  和 通知
 *                      切入点： 定义要拦截哪些类的哪些方法
 *                      通知： 定义拦截方法之后要做什么事情
 * @date 2021-11-29 20:53:12
 */
@Component
@Aspect
public class LogCut {

    /**
     * 定义切入点
     *      定义要拦截哪些类的哪些方法
     *   匹配规则： 拦截什么方法
     *
     * 定义切入点
     * @Pointcut("匹配规则")
     *
     * AOP 切入点表达式：
     *    execution(* org.com.wlc.service..*(..))
     *      第一个* 代表的是方法的修饰范围（public,private,protected）,如果取值是* 代表所有的范围
     *
     *    常见的表达式：
     *      1.执行所有的公共方法
     *       execution(public *(..))
     *      2.执行任意的setXX方法
     *       execution(* set*(..))
     *      3.执行指定包下的任意类的任意方法（指定包： org.com.wlc.service）
     *       execution(* org.com.wlc.service.*.*(..))
     *      4.设置包以及子类包下的任意类的任意方法
     *       execution(* org.com.wlc.service..*.*(..))
     */
    /** org.com.wlc.service 包下面的所有包下的所有类下的所有方法 */
    @Pointcut("execution(* org.com.wlc.service..*.*(..))")
    //@Pointcut("execution(* *.*(..))")
    public void cut(){

    }

    /**
     * 定义前置通知
     *     目标类的方法执行之前会执行前置通知
     */
    @Before(value = "cut()")
    public void before(){
        System.out.println("前置通知");
    }

    /**
     * 定义返回通知
     *   目标类执行后 无异常 返回后的通知
     */
    @AfterReturning(value = "cut()")
    public void afterReturn(){
        System.out.println("返回通知");
    }

    /**
     * 声明最终通知，并将通知应用在切入点上面
     *     目标类方法执行之后执行该通知
     *     无异常和有异常都会执行
     */
    @After(value = "cut()")
    public void after(){
        System.out.println("后置通知");
    }

    /**
     * 声明异常通知
     *    目标类方法执行有异常时候，执行该通知
     */
    @AfterThrowing(value = "cut()",throwing="e")
    public void afterThrow(Exception e){
        System.out.println("异常通知 -> "+ e.getMessage());
    }

    /**
     * 声明环绕通知
     *    目标类方法执行之前和执行之后，会执行该通知
     *    需要使用pjp.
     * @param pjp
     */
    @Around(value = "cut()")
    public Object around(ProceedingJoinPoint pjp){

        System.out.println("环绕通知-前置通知");
        Object object = null;
        try {
            // 显示调用对应的方法
            object = pjp.proceed();
            pjp.getTarget();
            System.out.println("焕荣通知-返回通知");
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            System.out.println("环绕通知的异常通知");
        }
        System.out.println("环绕通知执行-最终通知--");
        return object;
    }


}
